{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Sound;

interface

uses Classes, DSoundUtil, SysUtils;

const
  // Minimum playback delay period in milliseconds
  PLAYBACK_DELAY = 100;

type
  TAHMWAVSound = class
  private
    FSound: CSound;
  protected
  public
    destructor Destroy; override;
    function LoadFromFile(const Filename: String): Boolean;
    procedure PlaySound; overload;
    procedure PlaySound(Volume: Integer); overload;
    procedure StopSound;
  end;

implementation

uses Windows, Forms, Types, AHMTypes, Timing, DirectSound, Preferences;

const
  GUID_NULL : TGUID = '{00000000-0000-0000-0000-000000000000}';

var
  PlayingSound: Boolean;
  LastPlayed: TAHMTimestamp;

  FSoundManager: CSoundManager;

function SoundBufferFree: Boolean;
begin
  // Set default result - okay to Play
  Result := True;

  // Are we playing a sound?
  if not PlayingSound then
  begin
    // Not yet, timestamp this play event
    PlayingSound := True;
    LastPlayed := TimerInstance.CurrentTimeStamp;
  end
  else
  begin
    // Check elapsed time since last sound played. If sufficient time has
    // elapsed, write new timestamp otherwise we will keep waiting...
    if TimerInstance.HasDurationElapsed(LastPlayed, PLAYBACK_DELAY) then
      LastPlayed := TimerInstance.CurrentTimeStamp
    else
      Result := False;
  end;
end;

// TAHMWavSound

destructor TAHMWAVSound.Destroy;
begin
  FSound.Free;

  inherited Destroy;
end;

function TAHMWAVSound.LoadFromFile(const Filename: String): Boolean;
var
  hr: HRESULT;
begin
  // Set default result - failed to load
  Result := False;

  // Free any previous sound buffer instance
  FreeAndNil(FSound);

  // Load the wave file into a DirectSound buffer
  hr := FSoundManager.Create(FSound, PChar(Filename), DSBCAPS_CTRLVOLUME, GUID_NULL, 1);
  if FAILED(hr) then
  begin
    FreeAndNil(FSound);
    Exit;
  end;

  // Success - sound loaded into buffer
  Result := True;
end;

procedure TAHMWAVSound.PlaySound;
begin
  // Delegate to method below - play at max. volume
  PlaySound(DEF_SOUND_VOLUME);
end;

procedure TAHMWavSound.PlaySound(Volume: Integer);
var
  Attenuation: LongInt;
begin
  // Play sound asynchronously from our memory buffer
  if not SoundBufferFree then Exit;

  if Assigned(FSound) then
  begin
    // Convert volume to attenuation value (0..-100dB)
    Attenuation := Round((DEF_SOUND_VOLUME - Volume) / DEF_SOUND_VOLUME * -10000);
    if Attenuation < -10000 then Attenuation := -10000;
    if Attenuation > 0 then Attenuation := 0;

    FSound.Play(0, 0, Attenuation);
  end;
end;

procedure TAHMWAVSound.StopSound;
begin
  // Stop all wav sound playback
  if Assigned(FSound) then FSound.Stop;
end;


initialization
  // Clear flag to indicate we have played at least one sound
  PlayingSound := False;

  // Setup global sound manager instance
  FSoundManager := CSoundManager.Create;
  FSoundManager.Initialize(Application.Handle, DSSCL_PRIORITY);
  FSoundManager.SetPrimaryBufferFormat(2, 22050, 16);

finalization
  FSoundManager.Free;

end.
